﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;
using Weazel.Gezel.Model.Errors;
using Weazel.Math;

#endregion

namespace Weazel.Gezel.Parser
{
  public static class ParseConstant
  {
    public static Set<Token> First = new Set<Token>(Token.Constant);

    public static void Parse(Set<Token> follow, Tokenizer t, Model.Model model) 
    {
      Set<Token> current = new Set<Token>(
         // Token.Constant,
         Token.Identifier, 
         Token.Colon,
         Token.Assign,
         Token.Number,
         Token.Semicolon
      );
		
			Position startPosition = t.CurrentStartPosition;

      current = current.Union(ParseSignalType.First);
      t.Accept(Token.Constant, follow.Union(current));
      
      string name = t.CurrentToken == Token.Identifier ? t.CurrentString : null;
      current.Remove(Token.Identifier);
      t.Accept(Token.Identifier, follow.Union(current));
      
      current.Remove(Token.Colon);
      t.Accept(Token.Colon, follow.Union(current));
      
      current.Remove(ParseSignalType.First);
      SignalTypeInfo type = ParseSignalType.Parse(follow.Union(current), t);

      current.Remove(Token.Assign);
      t.Accept(Token.Assign, follow.Union(current));

      string value = t.CurrentToken == Token.Number ? t.CurrentString : null;
      t.Accept(Token.Number, follow.Union(Token.Semicolon));

			Position endPosition = t.CurrentEndPosition;

      t.Accept(Token.Semicolon, follow);

      // if all is well add the constant to the model
      if (name != null && value != null)
      {
        LeafExpression constant =
          new LeafExpression(
						ExpressionType.Constant, 
						value, 
						startPosition, 
						endPosition
					);

        // check that the identifier used has not been used elsewhere
        if (model.Constants.ContainsKey(name))
        {
          ErrorMessage message = new ErrorMessage();
          message.AddString("Duplicate defintion of constant '");
          message.AddEntity(constant);
          message.AddString("' at ");
          message.AddPosition(constant.StartPosition);
          message.AddString(". Previously defined at ");
          message.AddPosition(model.Constants[name].StartPosition);
          message.AddString(".");

          t.Errors.Add(
            new ParseError(
              ParseErrorType.DuplicateConstantDefinition,
              message
            )
          );
        }
        else
        {					
          model.Constants.Add(name, constant);
        }
      }
    }
  }
}
